package com.alan.wlmediaplayer;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.alan.wlmediaplayer.controller.WlMediaController;
import com.alan.wlmediaplayer.databinding.WlPlayerLayoutBinding;
import com.alan.wlmediaplayer.utils.WlSetting;
import com.alan.wlmediaplayer.utils.WlUtils;
import com.lib.basex.utils.Logger;
import com.lib.basex.widget.baselayout.LFrameLayout;
import com.ywl5320.wlmedia.WlMedia;
import com.ywl5320.wlmedia.enums.WlPlayModel;
import com.ywl5320.wlmedia.listener.WlOnCompleteListener;
import com.ywl5320.wlmedia.listener.WlOnDecryptListener;
import com.ywl5320.wlmedia.listener.WlOnErrorListener;
import com.ywl5320.wlmedia.listener.WlOnLoadListener;
import com.ywl5320.wlmedia.listener.WlOnPcmDataListener;
import com.ywl5320.wlmedia.listener.WlOnPreparedListener;
import com.ywl5320.wlmedia.listener.WlOnTakePictureListener;
import com.ywl5320.wlmedia.listener.WlOnTimeInfoListener;
import com.ywl5320.wlmedia.listener.WlOnVideoViewListener;

/**
 * @author Alan
 * 时 间：11/1/21
 * 简 述：<功能简述>
 */
public class WlMediaPlayerLayout extends LFrameLayout<String, WlPlayerLayoutBinding> implements WlOnPreparedListener,
        WlOnCompleteListener, WlOnDecryptListener, WlOnErrorListener, WlOnPcmDataListener, WlOnLoadListener,
        WlOnTakePictureListener, WlOnTimeInfoListener, WlOnVideoViewListener, WlSetting.OnWlMediaSettingChangedListener {

    /**
     * 播放错误
     **/
    public static final int STATE_ERROR = -1;
    /**
     * 撒打算大飒飒的阿斯顿
     * 播放未开始
     **/
    public static final int STATE_IDLE = 0;
    /**
     * 播放准备中
     **/
    public static final int STATE_PREPARING = 1;
    /**
     * 播放准备就绪
     **/
    public static final int STATE_PREPARED = 2;
    /**
     * 正在播放
     **/
    public static final int STATE_PLAYING = 3;
    /**
     * 暂停播放
     **/
    public static final int STATE_PAUSED = 4;
    /**
     * 正在缓冲(播放器正在播放时，缓冲区数据不足，进行缓冲，缓冲区数据足够后恢复播放)
     **/
    public static final int STATE_BUFFERING_PLAYING = 5;
    /**
     * 正在缓冲(播放器正在播放时，缓冲区数据不足，进行缓冲，此时暂停播放器，继续缓冲，缓冲区数据足够后恢复暂停
     **/
    public static final int STATE_BUFFERING_PAUSED = 6;
    /**
     * 播放完成
     **/
    public static final int STATE_COMPLETED = 7;

    /**
     * 切换视频源
     */
    public static final int STATE_CHANGING = 9;

    /**
     * 普通模式
     **/
    public static final int MODE_NORMAL = 10;
    /**
     * 全屏模式
     **/
    public static final int MODE_FULL_SCREEN = 11;
    /**
     * 小窗口模式
     **/
    public static final int MODE_TINY_WINDOW = 12;

    private int mCurrentMode = MODE_NORMAL;

    /**
     * 播放销毁
     **/
    public static final int STATE_DESTROY = 8;

    private int mCurrentState = STATE_IDLE;
    private WlMediaController mController;


    private String mUrl;
    private WlMedia mWlMedia;

    public WlMediaPlayerLayout(Context context) {
        super(context);
    }

    public WlMediaPlayerLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected int getContentId() {
        return R.layout.wl_player_layout;
    }

    public void setController(@NonNull WlMediaController mController) {
        this.mController = mController;
        this.mController.setMediaPlayerLayout(this);
        d.wlContainer.addView(mController, new RelativeLayout.LayoutParams(-1, -1));
    }

    @Override
    protected void initView(@Nullable AttributeSet attrs) {
        super.initView(attrs);
        setKeepScreenOn(true);
        mWlMedia = new WlMedia();
        d.wlSurfaceView.setWlMedia(mWlMedia);
        mWlMedia.setOnPreparedListener(this);
        mWlMedia.setOnCompleteListener(this);
        mWlMedia.setOnDecryptListener(this);
        mWlMedia.setOnErrorListener(this);
        mWlMedia.setOnLoadListener(this);
        mWlMedia.setOnPcmDataListener(this);
        mWlMedia.setOnTakePictureListener(this);
        mWlMedia.setOnTimeInfoListener(this);
        d.wlSurfaceView.setOnVideoViewListener(this);
        WlSetting.getInstance().setOnWlMediaSettingChangedListener(this);
    }


    public WlMediaPlayerLayout setUrl(String url) {
        this.mUrl = url;
        return this;
    }

    public void start() {
        Logger.d("start");
        if (mCurrentState == STATE_IDLE || mCurrentState == STATE_COMPLETED ||
                mCurrentState == STATE_ERROR || mCurrentState == STATE_CHANGING) {
            mWlMedia.setSource(mUrl);
            mWlMedia.prepared();
            setPlayState(STATE_PREPARING);
        } else if (mCurrentState == STATE_PAUSED) {
            mWlMedia.resume();
            setPlayState(STATE_PLAYING);
        } else if (mCurrentState == STATE_PLAYING) {
            mWlMedia.pause();
            setPlayState(STATE_PAUSED);
        }
    }

    @Override
    public void onPrepared() {
        Logger.d("onPrepared");
        if (mCurrentState == STATE_DESTROY) {
            return;
        }
        String[] audioChannels = mWlMedia.getAudioChannels();
        if (null != audioChannels) {
            WlSetting.getInstance().setChannelData(audioChannels);
        }
        mWlMedia.setAudioChannel(WlSetting.getInstance().getChannelIndex());
        double duration = mWlMedia.getDuration();
        mController.setTotalTime((long) duration);

        if (mCurrentState == STATE_PREPARING) {
            setPlayState(STATE_PLAYING);
            mWlMedia.start();
        } else if (mCurrentState == STATE_CHANGING) {
            mWlMedia.stop();
        }
    }

    @Override
    public void onComplete() {
        Logger.d("onComplete");
        if (mCurrentState == STATE_CHANGING) {
            start();
        } else {
            setPlayState(STATE_COMPLETED);
        }
    }

    @Override
    public byte[] decrypt(byte[] encrypt_data) {
        return new byte[0];
    }

    private int errorCode;
    private String errorMsg;

    /**
     * onError----code:-1;msg:the source is empty !
     * onError----code:-4;msg:the player is not in play !
     * onError----code:6002;msg:open source fail: Operation not permitted
     *
     * @param code
     * @param msg
     */
    @Override
    public void onError(int code, String msg) {
        if (mCurrentState == STATE_CHANGING) {
            start();
        } else {
            setPlayState(STATE_ERROR);
            this.errorCode = code;
            this.errorMsg = msg;
            Logger.d("onError----code:" + code + ";msg:" + msg);
        }
    }

    @Override
    public void onPcmInfo(int bit, int channel, int samplerate) {
        Logger.d("onPcmInfo-----bit:" + bit + ";channel:" + channel + ";samplerate:" + samplerate);
    }

    @Override
    public void onPcmData(int size, byte[] data) {
        Logger.d("onPcmData");
    }

    @Override
    public void onLoad(boolean load) {
        Logger.d("onLoad：" + load);
    }

    @Override
    public void takePicture(Bitmap bitmap) {
        Logger.d("takePicture");
    }

    @Override
    public void onTimeInfo(double currentTime) {
//        Logger.d("onTimeInfo" + currentTime);
        mController.setProgress((int) currentTime, false);
    }

    public void setPlayState(int state) {
        mCurrentState = state;
        if (mController != null) {
            mController.onPlayStateChanged(state);
        }
    }

    @Override
    public void initSuccess() {
        Logger.d("Surface View initSuccess");
    }

    @Override
    public void moveSlide(double value) {
        Logger.d("Surface View moveSlide");
    }

    @Override
    public void movdFinish(double value) {
        Logger.d("Surface View movdFinish");
    }

    public void seek(int position) {
        mWlMedia.seek(position);
    }

    public void enterFullScreen() {
        if (mCurrentMode == MODE_FULL_SCREEN) {
            return;
        }
        WlUtils.hideActionBar(getContext());
        WlUtils.scanForActivity(getContext())
                .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        ViewGroup contentView = WlUtils.scanForActivity(getContext())
                .findViewById(android.R.id.content);
        d.myContainer.removeView(d.wlContainer);
        contentView.addView(d.wlContainer, new ViewGroup.LayoutParams(-1, -1));
        mCurrentMode = MODE_FULL_SCREEN;
        mController.onPlayModeChanged(mCurrentMode);
    }

    public boolean exitFullScreen() {
        if (mCurrentMode == MODE_FULL_SCREEN) {
            WlUtils.showActionBar(getContext());
            WlUtils.scanForActivity(getContext())
                    .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

            ViewGroup contentView = (ViewGroup) WlUtils.scanForActivity(getContext())
                    .findViewById(android.R.id.content);
            contentView.removeView(d.wlContainer);
            LayoutParams params = new LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            d.myContainer.addView(d.wlContainer, params);

            mCurrentMode = MODE_NORMAL;
            mController.onPlayModeChanged(mCurrentMode);
            return true;
        }
        return false;
    }


    public boolean isFullScreen() {
        return mCurrentMode == MODE_FULL_SCREEN;
    }

    public String[] getAudioChannel() {
        return mWlMedia.getAudioChannels();
    }

    public void release() {
        if (mWlMedia.isPlay()) {
            mWlMedia.stop();
        }
        setPlayState(STATE_DESTROY);
        mWlMedia.release();
        mController = null;
    }

    @Override
    public void onChannelChangedListener(int index) {
        mWlMedia.setAudioChannel(index);
    }

    public void pause() {
        if (mCurrentState == STATE_PLAYING) {
            mWlMedia.pause();
            setPlayState(STATE_PAUSED);
        } else if (mCurrentState == STATE_PREPARING || mCurrentState == STATE_PREPARED) {
            setPlayState(STATE_PAUSED);
        }
    }

    @Override
    public void onScreenSizeChangedListener(int index) {
        if (index == 0) {
            mWlMedia.scaleVideo(mWlMedia.getVideoWidth(), mWlMedia.getVideoHeight());
        } else if (index == 1) {
            mWlMedia.scaleVideo(16, 9);
        } else if (index == 2) {
            mWlMedia.scaleVideo(4, 3);
        }
    }

    @Override
    public void onSpeedChangedListener(int index) {
        float speed = 1.0f;
        switch (index) {
            case 0:
                speed = 0.5f;
                break;
            case 1:
                speed = 1f;
                break;
            case 2:
                speed = 1.5f;
                break;
            case 3:
                speed = 2f;
                break;
        }
        mWlMedia.setSpeed(speed);
    }

    @Override
    public void onPlayModeChangedListener(int index) {
        mWlMedia.stop();
        WlPlayModel model = WlPlayModel.PLAYMODEL_AUDIO_VIDEO;
        switch (index) {
            case 0:
                model = WlPlayModel.PLAYMODEL_AUDIO_VIDEO;
                break;
            case 1:
                model = WlPlayModel.PLAYMODEL_ONLY_VIDEO;
                break;
            case 2:
                model = WlPlayModel.PLAYMODEL_ONLY_AUDIO;
                break;

        }
        mWlMedia.setPlayModel(model);
    }

    @Override
    public void onPlayColorChangedListener(int index) {
        switch (index) {
            case 0:
                filterNormal();
                break;
            case 1:
                filterGray();
                break;
            case 2:
                filterInversion();
                break;
        }
    }

    private void filterNormal() {
        String fs = "precision mediump float;" +
                "varying vec2 ft_Position;" +
                "uniform sampler2D sTexture; " +
                "void main() " +
                "{ " +
                "gl_FragColor = texture2D(sTexture, ft_Position);" +
                "}";
        mWlMedia.setfShader(fs);
        mWlMedia.changeFilter();
    }

    private void filterGray() {
        String fs = "precision mediump float;" +
                "varying vec2 ft_Position;" +
                "uniform sampler2D sTexture; " +
                "void main() " +
                "{ " +
                "vec4 v=texture2D(sTexture, ft_Position); " +
                "float average = (v.r + v.g + v.b) / 3.0;" +
                "gl_FragColor = vec4(average, average, average, v.a);" +
                "}";
        mWlMedia.setfShader(fs);
        mWlMedia.changeFilter();
    }

    private void filterInversion() {
        String fs = "precision mediump float;" +
                "varying vec2 ft_Position;" +
                "uniform sampler2D sTexture; " +
                "void main() " +
                "{ " +
                "vec4 v=texture2D(sTexture, ft_Position); " +
                "gl_FragColor = vec4(vec3(1.0 - v), v.a);" +
                "}";
        mWlMedia.setfShader(fs);
        mWlMedia.changeFilter();
    }

    public int getErrorCode() {
        return errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public int getVolume() {
        return mWlMedia.getVolume();
    }

    public int getDuration() {
        return (int) mWlMedia.getDuration();
    }

    public void setVolume(int volume) {
        mWlMedia.setVolume(volume);
    }

    public int getCurrentPosition() {
        return (int) mWlMedia.getNowClock();
    }

    public boolean isPlaying() {
        return mCurrentState == STATE_PLAYING;
    }

    public void reset() {
        if (mWlMedia.isPlay()) {
            mWlMedia.stop();
        }
        if (mCurrentState != STATE_IDLE) {
            setPlayState(STATE_IDLE);
        }
    }

    public void change(String url) {
        setUrl(url);
        if (mCurrentState == STATE_IDLE || mCurrentState == STATE_COMPLETED || mCurrentState == STATE_ERROR || mCurrentState == STATE_PREPARED) {
            start();
        } else if (mCurrentState == STATE_PAUSED || mCurrentState == STATE_PLAYING || mCurrentState == STATE_PREPARING) {
            mWlMedia.stop();
            setPlayState(STATE_CHANGING);
        }
    }
}
